<?php
namespace App\GameService\games;

use App\Common\GameCommon;
use App\Utility\BaseEnum;
use App\Common\AuthCommon;
use Swoole\Timer;
use App\Utility\RedisTools;
use App\Common\BaseComm;
use App\Enum\CardEnum;
use App\Enum\SysEnum;

/**
 * 通比牛牛游戏
 *
 * @author Administrator
 */
class PlayTbNiuNiu extends BasePlay
{

    protected $plyerQZLong = 10;

    // 抢庄10秒
    protected $playerBetTimer;

    protected $createcardsTimer;

    protected $palycenterTimer;

    protected $playerBetTimer_long = 8;

    // 下注时长
    protected $palycenterTimer_long = 15;

    // 结算时长

    // 事件
    public function __construct() {
    }

    /**
     * 看牌提前发三张牌
     *
     * @param array $playFds
     * @param array $useCards
     */
    protected function PushFrontThreeCards($playFds, $useCards = FALSE)
    {
        if (! $useCards || empty($useCards))
            return false; // 推送每个位置的牌值；
        foreach ($useCards as $onecards) {
            $seatid = isset($onecards["seatNo"]) ? intval($onecards["seatNo"]) : - 1; // 座位号
            $cards = isset($onecards["cards"]) ? $onecards["cards"] : FALSE;
            if (! empty($cards) && sizeof($cards) > 3 && $seatid >= 0 && isset($playFds[$seatid])) {
                $oneCard = [
                    "seatNo" => $seatid,
                    "cards" => array_slice($cards, 0, 3),
                    "step" => 0
                ]; // 只取前三张牌
                AuthCommon::pushFrontWeb($playFds[$seatid], json_encode([
                    'm' => BaseEnum::XYM_0X17,
                    "data" => $oneCard
                ])); // 推送相同内容
            }
        }
        return true;
    }

    /**
     * 开始游戏入口；
     * 必须实现这个方法；
     * 游戏开始逻辑
     */
    public function asycStartGame($gameNo, $gameRId = FALSE, $fjInfo = FALSE, &$commonLoopTimer = 0)
    {
        
        exit('等待开发');
        $gameId = isset($fjInfo['gameId']) ? intval($fjInfo['gameId']) : 0;
        $gameAllData = BaseComm::distMemoryRooms($gameNo, FALSE); // 内存数据；
        $fjSta = isset($gameAllData['fjStatus']) ? intval($gameAllData['fjStatus']) : 0;
        $gamePlays = isset($gameAllData['lists']) ? $gameAllData['lists'] : FALSE; // 玩家列表；
        $playFds = ! empty($gamePlays) ? array_column($gamePlays, "fd", "seatNo") : false; // 座位列表
        BaseEnum::Logger('取内存数据:Games-(PlayNiuNiu)-[asycStartGame]--->>>' . json_encode($gameAllData), 'user-login');

        // 刚开始就给玩家生成牌的数据；
        $useCards = GameCommon::createCardList($gameId, $gameNo, false); // 启动发牌 ： XYM_0X19；
        BaseEnum::Logger("游戏开始生成牌:Games-(PlayNiuNiu)-{$gameId} 再计算计算谁是[{$gameNo}]庄主---->>>" . json_encode($useCards), 'user-login'); // 所有玩家FD
        if ($gameId === 201) {
            $this->PushFrontThreeCards($playFds, $useCards); // 看牌抢庄牛 === > 发3张牌（前三张）；
        }
        $Parms = [
            "gameNo" => $gameNo,
            "clientIds" => $playFds,
            "status" => $fjSta
        ];

        // 抢庄====倒计时10秒钟
        $this->asycTimeStart($this->plyerQZLong, $gameNo, $Parms, function () use ($gameNo, $gameRId, $gamePlays, $playFds, $fjInfo, $useCards) {
            $error = '';
            $notQzUser = FALSE;
            if (! $fjInfo) {
                $fjInfo = BaseComm::GameRoomDetail($gameRId);
            }
            $gameId = isset($fjInfo['gameId']) ? intval($fjInfo['gameId']) : 0;
            BaseEnum::Logger("选庄家定时器：Games-(PlayNiuNiu)-==========>  ，计算谁是[{$gameNo}]庄主---->>>" . json_encode($playFds), 'user-login'); // 所有玩家FD
            Timer::clear($this->baseOneTimer);
            // 计算谁是庄家；
            $zjUser = GameCommon::countRoomMaimZhuang($gameNo, $gamePlays, $notQzUser);
            $zjUid = isset($zjUser['uid']) ? intval($zjUser['uid']) : 0; // 抢到倍数大于0
            $zjSeatid = isset($zjUser['seatNo']) ? intval($zjUser['seatNo']) : - 1; // 抢到倍数大于0
            $zjMuts = isset($zjUser['mutdotts']) ? intval($zjUser['mutdotts']) : 0; // 抢到倍数大于0
            $zjPoints = isset($zjUser['points']) ? floatval($zjUser['points']) : 0; // 抢到倍数大于0
            BaseEnum::Logger("抢庄统计：Games-(PlayNiuNiu)-哪些用户没有千抢庄 ===> " . json_encode($notQzUser), 'user-login');
            if (! empty($notQzUser)) {
                // 显示不抢庄的玩家
                foreach ($notQzUser as $onenotxj) {
                    AuthCommon::pushFrontWeb($playFds, json_encode([
                        'm' => BaseEnum::XYM_0X18,
                        "data" => $onenotxj
                    ])); // 推送不抢庄
                }
            }
            if (isset($zjUser) && $zjUid > 0 && isset($zjUser['fd']) && intval($zjUser['fd']) > 0 && ! empty($playFds) && $zjMuts > 0 && $zjPoints > 0) { // 抢zhuang 成功
                $totalNum = sizeof($playFds); // 通知给所有玩家，谁是庄家；
                $showList = array(
                    "seatNo" => $zjSeatid,
                    "mutdotts" => $zjMuts,
                    "max_mutle" => 10,
                    "nums" => $totalNum
                ); // 最大下注倍数
                   // 抢zhuang 成功； 计算每个用户最大倍数（要等玩家匹配成功才能计算的）；
                $maxBet_Mult = CardEnum::countDeskMaxMutle($totalNum, $zjMuts, $zjPoints, $fjInfo);
                $showList["max_mutle"] = ($maxBet_Mult > 0) ? $maxBet_Mult : rand(5, 8);
                // 游戏记录写DB数据; ======> 记录玩家中谁是庄家及倍数；
                $savedata = array(
                    "ptype" => 1,
                    "userId" => $zjUid,
                    "data" => $zjMuts
                );
                $maxut = GameCommon::updateRoomsPInfo($gameNo, $savedata, $gamePlays, $error);

                // 抢成功才会到下一步
                if (isset($maxut) && $maxut === true) {
                    // 推送到所有FD，庄家的座位号；[XYM_0X19 --抢庄成功 ]
                    BaseEnum::Logger("抢庄成功：Games-(PlayNiuNiu)-恭喜用户 UID={$zjUid} 抢庄(QZ：{$zjMuts}倍)成功---->>> SUCCESS !!!!" . $gameNo, 'user-login');
                    AuthCommon::pushFrontWeb($playFds, json_encode([
                        'm' => BaseEnum::XYM_0X1A,
                        "data" => $showList
                    ])); // 推送相同内容
                    $zjUserInfo = array(
                        "uid" => $zjUid,
                        "seatNo" => $zjSeatid,
                        "bet_mutle" => $zjMuts,
                        "main_flag" => 1
                    ); // 标识为庄主

                    // 启动下一个定时器；======> 闲家选倍数；
                    $this->StartUserBetMuts($gameId, $gameRId, $gameNo, $gamePlays, $zjUid, $zjUserInfo, $useCards);
                } else {
                    // 异常失败
                    AuthCommon::pushFrontWeb($playFds, json_encode([
                        'm' => $maxut,
                        "data" => null,
                        "msg" => $error
                    ])); // 推送相同内容
                }
            } else {
                BaseEnum::Logger('抢庄失败：PlayNiuNiu-(asycStartGame)-执行定时器计算抢庄失败 ---->>>Fail !!!!' . $gameNo, 'user-login');
            }
        });
    }

    
    /**
     * 游戏玩家下注实现(下注把倍数存入内存中处理)
     * @param string $gameNo
     * @param int $roomId
     * @param boolean $params
     */
    public function asycPlayBets($roomId,$gameNo,$params = FALSE,& $errorNo = -1){
        $userId = isset($params['loginUid']) ? intval($params['loginUid']) : 0 ;
        $qmutil = isset($params['qmutil']) ? intval($params['qmutil']) : 1 ; //下注倍数
        if (!$roomId || empty($gameNo) || empty($params) || $userId <= 0) {
            return  FALSE;
        }
        $gameDetail = BaseComm::distMemoryRooms($gameNo, FALSE);        // 内存数据；
        $fjStatus = isset($gameDetail['fjStatus']) ? intval($gameDetail['fjStatus']) : 0;
        $users = isset($gameDetail['lists']) ? $gameDetail['lists'] : FALSE;
        
        
        //庄家ID
        $zjUid = 0 ;
        if(!empty($users)){
            foreach ( $users as $oneuu ){
                if(isset($oneuu['uid']) && intval($oneuu['uid'])>0 && isset($oneuu['mainflag']) && intval($oneuu['mainflag'])==1){
                    $zjUid = intval($oneuu['uid']) ;
                    break;
                }
            }
        }
        
        
        BaseEnum::Logger("游戏数据 : (asycPlayBets - [{$gameNo}])==>" . json_encode($gameDetail), 'user-login');
        if (!$gameDetail || !$users) {
            $errorNo = BaseEnum::MSG_0XFA;
            return FALSE;
        }
        
        //非下注状态；
        if(!$fjStatus || $fjStatus !== 1 ){
            $errorNo = BaseEnum::MSG_0XFD;
            return FALSE;
        }
        
        //庄家不能下注
        if ($zjUid == $userId) {
            $errorNo = BaseEnum::MSG_0XF2;
            return FALSE;;
        }
        
        
        
        $userSeat = array_column($users, "seatNo","uid");
        $userFds = array_column($users, "fd","seatNo");
        
        //TODO 实现下注；写入数据进到内存中（结构:lists为玩家信息，bets 下注列表）
        $userBets  = isset($gameDetail['bets']) ? $gameDetail['bets'] :  [];
        $pushObj = FALSE;
        foreach ($userSeat as $uuid => $seatIndex){
            if ($uuid && intval($uuid) === $userId) {
                $userBets[$seatIndex] = $qmutil ; //下注倍数存起放在内存中
                $pushObj = [ "seatNo" => $seatIndex, "mutdotts" => $qmutil, "p_fd" => $userId];
                break;
            }
        }
        
        //下注数据存起来
        $gameDetail['bets'] = $userBets;
        BaseComm::distMemoryRooms($gameNo,TRUE,$gameDetail);
        
        // 下注信息
        $pushData = array( "m" => BaseEnum::XYM_0X19, "data" => $pushObj );
        BaseEnum::Logger("牛牛玩家下注成功 : (asycPlayBets - [{$gameNo}])==>" . json_encode($userBets), 'user-login');
        AuthCommon::pushFrontWeb($userFds, json_encode($pushData)); // 通知给所有玩家，谁在抢庄；
        
        //TODO  下注人员都满员启动提前结束定时器
        if(!empty($userBets) && sizeof($userBets) > 0 &&  sizeof($userBets) + 1 >= sizeof($userSeat)){
            PlayHelp::getInstance()->setCommTimerStop($gameNo,true);    //停掉定时器
            BaseEnum::Logger("所有玩家下注完成：========：(asycPlayBets) -- [ STOP ]-RoomId=". $gameNo ."  =======================设置为1,中断操作========>>>>>>", 'user-login');
        }
        
        return TRUE;
    }
    
    /**
     * 进入下一步处理事件
     */
    public function doNextPlayBets($loginFd, $gameNo, $fjDetail = FALSE, $getUix = FALSE)
    {
        // 动画处理完触发；只能调用一次；触发动画倒计时；
        $fjSta = isset($fjDetail['fjStatus']) ? intval($fjDetail['fjStatus']) : 0;
        $gamePlays = isset($fjDetail['lists']) ? $fjDetail['lists'] : FALSE; // 玩家列表；
        $playerFds = ! empty($gamePlays) ? array_column($gamePlays, "fd", "seatNo") : false; // 座位列表
        $Parms = [
            "gameNo" => $gameNo,
            "clientIds" => $playerFds,
            "status" => $fjSta
        ];
        $zjUserInfo = FALSE;
        if (! empty($gamePlays) && sizeof($gamePlays) >= 2) { // 查找庄家信息；
            foreach ($gamePlays as $oneuser) {
                if (isset($oneuser["uid"]) && intval($oneuser["uid"]) > 0 && isset($oneuser["mainflag"]) && intval($oneuser["mainflag"]) === 1) { // 庄家 mainflag = 1
                                                                                                                                                  // 庄家的倍数
                    $zjUserInfo = array(
                        "uid" => $oneuser["uid"],
                        "seatNo" => @$oneuser["seatNo"],
                        "bet_mutle" => isset($oneuser['mutdotts']) ? intval($oneuser['mutdotts']) : 0,
                        "main_flag" => 1 // 标识为庄主;
                    );
                    break;
                }
            }
        }
        // 标识为庄主;
        if (! $zjUserInfo || ! isset($zjUserInfo['uid']) || intval($zjUserInfo['uid']) <= 0)
            return FALSE;

        $this->asycTimeStart($this->playerBetTimer_long, $gameNo, $Parms, function () use ($gameNo, $gamePlays, $playerFds, $fjDetail, $zjUserInfo) {
            $userBetInfo = [];
            $zjUserid = isset($zjUserInfo["uid"]) ? intval($zjUserInfo["uid"]) : 0;
            $gameId = isset($fjDetail["gameId"]) ? intval($fjDetail["gameId"]) : 0; // 游戏ID值；
            $gameRId = isset($fjDetail["grid"]) ? intval($fjDetail["grid"]) : 0; // 房间ID值；
            $useCards = isset($fjDetail["frontCards"]) ? $fjDetail["frontCards"] : FALSE; // 提前发的牌数据
            
            //房间内的数据
            $gameDetail = BaseComm::distMemoryRooms($gameNo,FALSE);
            $userBets  = isset($gameDetail['bets']) ? $gameDetail['bets'] :  [];            //下注的数据内容
            $gamePlays = isset($gameDetail['lists']) ? $gameDetail['lists'] : FALSE;        // 玩家列表；
            
            $allSeat = array_column($gamePlays, 'seatNo',"uid");
            
            /**
             * TODO 下注==== 玩家下注TO DB
             * 实际步骤：
             * 1、检查所有玩家是否有下注和下注倍数据
             * 2、把没有下注完的默认下1倍；并推给所有玩家
             */
            BaseEnum::Logger("执行定时器计算：PlayNiuNiu-(asycStartUserBetMuts)-=====[投注倍数]  ，去列队中给[{$gameNo}]所有玩家下单--（DB）-->>>" . json_encode($playerFds), 'user-login');
            BaseEnum::Logger('取内存数据：PlayNiuNiu-[asycStartUserBetMuts]--->>>' . json_encode($gameDetail), 'user-login');
            
            
            $userBetIds = [];
            $noticeUsers = [];
            //TODO 计算未下注的用户信息
            foreach ($allSeat as $uuid => $setid2){
                if (isset($uuid) && intval($uuid)>0 && intval($uuid) === $zjUserid) continue;
                $usrbetMul = isset($userBets[$setid2]) ? intval($userBets[$setid2]) : 0;        //下注倍数
                if($uuid > 0 && $usrbetMul <= 0 ){
                    $usrbetMul = 1;
                    $userBets[$setid2] = 1 ;
                    $noticeUsers[$uuid] = array("uid" =>$uuid,"seatNo" =>$setid2, "bet_mutle" => 1);        //未下注
                }
                $userBetIds[] = $uuid;   //下注列表
            }
            
            
            //TODO 修改内存中游戏状态
            foreach ($gamePlays as $setiid => &$oneplay) {
                if (isset($userBets[$setiid]) && intval($userBets[$setiid]) > 0) {
                    $oneplay["mutdotts"] = intval($userBets[$setiid]);       // 修改下注倍数
                    $oneplay["pstatus"] = CardEnum::GAME_STEP_2;             // 修改下注成功；
                }
            }
            $gameDetail['bets'] = $userBets;
            $gameDetail['fjStatus'] = CardEnum::GAME_STEP_2;                // 下注成功
            $gameDetail['lists'] = $gamePlays;
            BaseComm::distMemoryRooms($gameNo,TRUE,$gameDetail);            //TODO 存储游戏数据
            BaseEnum::wirteRedisData(SysEnum::ONLINE_ROOMS_LIST_KEY . $gameNo, json_encode($gameDetail));
            
            $error = -1;
            
            //TODO 所有玩家订单入库处理： (闲家下注)
            $savedata = array("ptype"=> 2 ,"userId" => implode(',', $userBetIds) ,"data"=> $userBets);
            $dbFlag = GameCommon::updateRoomsPInfo($gameNo,$savedata,$gamePlays,$error);  //下注成功；
            
            if ($dbFlag !== TRUE) {
                BaseEnum::Logger("闲家下注失败：(下注) ->>> ERROR -- {$error}，  未下注玩家：" . json_encode($noticeUsers), 'user-login');
                $userBetInfo[$zjUserid] = $zjUserInfo; // 合并庄家的ID
                return FALSE;
            }
            
            // TODO 单个数据推到前端；
            $allFds = array_column($gamePlays, "fd","seatNo");
            if (! empty($noticeUsers)) {
                $noticeUsers = array_column($noticeUsers, null, "seatNo");  // 通知给所有玩家，下注倍数；
                foreach ($noticeUsers as $siteid => $oneline) {
                    $oneInfo = [ "seatNo" => $siteid, "mutdotts" => isset($oneline['bet_mutle']) ? intval($oneline['bet_mutle']) : 1, "self" => 1];
                    $pushdata = ['m' => BaseEnum::XYM_0X19, "data" => $oneInfo];
                    AuthCommon::pushFrontWeb($allFds, json_encode($pushdata));   // 推送未下注玩家默认1倍
                }
            }
            
            // TODO 启动摇色子[XYM_0X30]
            Timer::after(2000, function() use($gameId, $gameRId, $gameNo,$allFds,$useCards){
                
                BaseEnum::Logger("启动发牌：(只发每个人的手牌) ->>> Start，  INFO：" . json_encode([$gameId, $gameRId, $gameNo]), 'user-login');
                $this->StartCards($gameId, $gameRId, $gameNo, $allFds, $useCards);
            });
        });
    }

    /**
     * 掉线重连操作
     *
     * @param int $userid
     * @param int $loginFd
     * @param string $newGameNo
     */
    public function reConnectPlay($userid, $loginFd, $gameNo = FALSE)
    {
        if (! $gameNo || $userid <= 0)
            return FALSE; // 玩家最新游戏ID对应的号
        $fjData = BaseComm::distMemoryRooms($gameNo, FALSE);
        $gameId = isset($fjData['gameId']) ? intval($fjData['gameId']) : 0;
        $gameStatus = isset($fjData['fjStatus']) ? intval($fjData['fjStatus']) : 0;
        $gamePlays = isset($fjData['lists']) ? $fjData['lists'] : FALSE;
        // 只要游戏没有结束就换掉用户的客户端FD值，否则推送出错；
        if (! empty($gamePlays)) {
            foreach ($gamePlays as $r => $oneline) {
                if (isset($oneline['uid']) && intval($oneline['uid']) === $userid) {
                    $gamePlays[$r]['fd'] = $loginFd; // 当前登录用户的客户FD值；
                }
            }
            $fjData['lists'] = $gamePlays; // 修改后的数据重新给值
            BaseComm::distMemoryRooms($gameNo, TRUE, $fjData); // 保存数据
                                                               // 游戏数据恢复
            BaseEnum::Logger("掉线重连：PlayNiuNiu --> reConnectPlay-[{$userid},$gameId ,$gameNo]-------gameData-->" . json_encode($fjData), 'user-login');
            // 查询当前游戏状态：
            if (! empty($fjData) && $gameStatus >= 0 && in_array($gameStatus, [
                0,
                1,
                2,
                3,
                4,
                5
            ])) { // 大于1 都是游戏中；
                $steps = BaseEnum::GAME_STEP;
                $stepName = isset($steps[$gameStatus]) ? $steps[$gameStatus] : "-";
                BaseEnum::Logger("掉线重连：PlayNiuNiu --> 当前状态：-[{$stepName},$gameNo]-------status-->" . $gameStatus, 'user-login');
                // 显示游戏中的数据结构：定义新的结构；
                $returnData = array(
                    "gameNo" => $gameNo,
                    "step" => $stepName,
                    "status" => $gameStatus,
                    "lists" => []
                );
                // 恢复游戏数据： 只处理以下几张情况；
                // 1、抢庄中---谁庄过庄（标识出来），
                // 2、下注中(谁是庄家标识出来，)
                // 3、结算中(庄家，下注倍数，当前玩家牌值内容)
                $gameResult = $this->reBackData($userid, $gameStatus, $gameNo, $gamePlays);
                BaseEnum::Logger("掉线重连：PlayNiuNiu --> 数据恢复：-[{$gameNo}]-------status-->" . json_encode($gameResult), 'user-login');
                if (! $gameResult) {
                    return FALSE;
                }
                // 显示每个玩家的数据内容；
                $returnData["lists"] = $gameResult;
                return $returnData;
            }
        }
        return FALSE;
    }

    /**
     * 恢复游戏数据；
     * 处理以下几张情况；
     * 1、抢庄中---谁庄过庄（标识出来），
     * 2、下注中(谁是庄家标识出来，)
     * 3、结算中(庄家，下注倍数，当前玩家牌值内容)
     *
     * 附状态值：0 => '匹配', 1 => '抢庄', 2 => '下注', 3 => '发牌', 4 => '拼牌', 5 => '结算',
     *
     * @param int $gameStatus
     * @param array $gamePlays
     */
    protected static function reBackData($loginUid, $gameStatus, $gameNo = FALSE, $gamePlays = FALSE)
    {
        if (! $loginUid || ! $gamePlays || ! $gameNo)
            return false;
        $redisobj = new RedisTools();
        $redisobj->select(0);
        $palyUser = $gamePlays;
        foreach ($palyUser as & $oneus) {
            unset($oneus['fd']);
            unset($oneus['agentId']);
            unset($oneus['betmoney']);
        }
        // 匹配成功 开始抢庄 ===> 谁有抢庄
        if ($gameStatus === CardEnum::GAME_STEP_0) {
            $rediskey = SysEnum::ONLINE_BDATA_KEY . "_MUT"; // 查询下注数据；
            $betdata = $redisobj->hGet($rediskey, $gameNo);
            $betArray = ! empty($betdata) ? json_decode($betdata, TRUE) : FALSE;
            foreach ($palyUser as $sid => $oneuser) {
                $palyUser[$sid]['pstatus'] = '玩家抢庄';
            }
        } // 抢庄完成 开始下注 ===> 标出谁是庄家,闲家下注倍数；
        else if ($gameStatus === CardEnum::GAME_STEP_1) {
            $rediskey = SysEnum::ONLINE_BDATA_KEY . "_MUT"; // 查询下注数据；
            $betdata = $redisobj->hGet($rediskey, $gameNo);
            $betArray = ! empty($betdata) ? json_decode($betdata, TRUE) : FALSE;
            foreach ($palyUser as $sid => $oneuser) {
                $palyUser[$sid]['pstatus'] = '闲家下注';
                if (isset($oneuser['mainflag']) && intval($oneuser['mainflag']) == 1) { // 定庄：uid,
                    $palyUser[$sid]['text'] = '庄';
                    $palyUser[$sid]['pstatus'] = '等待闲家下注';
                } else {
                    $palyUser[$sid]['text'] = '闲';
                    $palyUser[$sid]['mutdotts'] = isset($betArray[$sid]) ? intval($betArray[$sid]) : 0; // 闲家下注倍数
                    $palyUser[$sid]['max_mutle'] = 15; // 最大下注倍数；
                }
            }
        } // 下注完成 开始发牌 拼牌 ===> 开始发牌（显示下注倍数）
        else if (in_array($gameStatus, [
            CardEnum::GAME_STEP_2,
            CardEnum::GAME_STEP_3
        ], true)) {
            $cards = BaseComm::distMemoryCards($gameNo, FALSE); // 全局变量获取手牌数据（座位号seatNo=> [11,23,233]）
            foreach ($palyUser as $sid => $oneuser) {
                $palyUser[$sid]['pstatus'] = ($gameStatus == 3) ? "拼牌中" : '发牌中';
                $palyUser[$sid]['ifcards'] = 1; // 已发牌
                $palyUser[$sid]['cards'] = false; // 已发牌
                if (isset($oneuser['uid']) && intval($oneuser['uid']) == $loginUid) { // 显示发给我的手牌；
                    $palyUser[$sid]['cards'] = isset($cards[$sid]) ? $cards[$sid] : [];
                }
            }
        } // 拼牌完成 摊牌 ===> 结算数据（显示玩家最后的结算数据）
        else if (in_array($gameStatus, [
            CardEnum::GAME_STEP_4,
            CardEnum::GAME_STEP_5
        ], true)) {
            $cards = BaseComm::distMemoryCards($gameNo, FALSE); // 全局变量获取手牌数据（座位号seatNo=> [11,23,233]）
            foreach ($palyUser as $sid => $oneuser) {
                $palyUser[$sid]['pstatus'] = "结算中";
                $palyUser[$sid]['ifcards'] = 1; // 已发牌
                $palyUser[$sid]['cards'] = isset($cards[$sid]) ? $cards[$sid] : [];

                // 显示结算所的金额数据；
                $palyUser[$sid]['lastmoney'] = 0.01;
            }
        }
        return $palyUser;
    }

    /**
     * 异步监控房间内下注
     * asycStartUserBetMuts
     */
    protected function StartUserBetMuts($gameId, $gameRId, $gameNo, $players = false, $zjUserid = 0, $zjUserInfo = false, $useCards = FALSE)
    {
        BaseEnum::Logger('闲家异步统计：PlayNiuNiu-(StartUserBetMuts)-统计 ---->>>>>>>>>>>>> 待完善:' . $gameNo, 'user-login');
        // 8秒动画效果；
        Timer::after(10000, function () use ($gameNo, $gameId) {
            $fjDetail = BaseComm::distMemoryRooms($gameNo); // 房间内的信息；

            // 查看当前状态是否启动；
            if (isset($fjDetail["doNext"]) && intval($fjDetail["doNext"]) > 0) { // 已经处理过了；
                BaseEnum::Logger('异步自动下注执行：PlayNiuNiu-(StartUserBetMuts)-[检查到doNext=1 已经执行处理过，不再处理]--->>>' . json_encode($fjDetail), 'user-login');
            } else {
                $fjDetail["doNext"] = 1;
                BaseComm::distMemoryRooms($gameNo, true, $fjDetail); // 保存标识不允许再次发起
                $this->doNextPlayBets(null, $gameNo, $fjDetail, 0);
            }
        });
    }

    /**
     * 开始发牌操作；
     *
     * @param array $paramList
     */
    protected function StartCards($gameId, $gameRId, $room_No, $playerFds = false, $useCards = FALSE)
    {
        $playerCards = [];
        $getAlldata = BaseComm::distMemoryRooms($room_No, FALSE);
        BaseEnum::Logger('取内存数据：PlayNiuNiu--[StartCards]--->>>' . json_encode($getAlldata), 'user-login');
        // 启动发牌；======> 操作代码 ： XYM_0X19；
        if (empty($useCards)) {
            BaseEnum::Logger("重新启动发牌：PlayNiuNiu-(StartCards)-；===={$gameRId}==>{$room_No}| XYM_0X19 --> ==allUserFds : " . json_encode($playerFds), 'user-login');
            $useCards = GameCommon::createCardList($gameId, $room_No, false);
        } else {
            BaseEnum::Logger("发牌推送：PlayNiuNiu-(StartCards)-；===={$gameRId}==>{$room_No}| XYM_0X19 --> ==data : " . json_encode($useCards), 'user-login');
        }
        
        // 发牌
        if (isset($useCards) && ! empty($useCards)) {
            $getAlldata['fjStatus'] = CardEnum::GAME_STEP_3; // 修改为发牌成功；
            if (isset($getAlldata['lists']) && ! empty($getAlldata['lists'])) {
                $playerFds = array_column($getAlldata['lists'], "fd", "seatNo"); // 使用最新数据
                foreach ($getAlldata['lists'] as $setiid => $fg) {
                    $getAlldata['lists'][$setiid]["pstatus"] = CardEnum::GAME_STEP_3;
                }
            }
            BaseComm::distMemoryRooms($room_No, TRUE, $getAlldata); // 保存用户数据
            BaseEnum::wirteRedisData(SysEnum::ONLINE_ROOMS_LIST_KEY . $room_No, json_encode($getAlldata)); // 缓存；
            // 分发给每个用户(发牌代号：BaseEnum::XYM_0X1C )
            foreach ($useCards as $pushOneMsg) {
                $fullC = "";
                $seatId = isset($pushOneMsg['seatNo']) ? intval($pushOneMsg['seatNo']) : 0;
                $curUfd = isset($playerFds[$seatId]) ? intval($playerFds[$seatId]) : 0;
                if ($seatId !== false && $seatId >= 0 && isset($pushOneMsg['cards']) && ! empty($pushOneMsg['cards'])) {
                    $oneCards = $pushOneMsg['cards'];
                    if ($gameId === 201 && ! empty($oneCards) && sizeof($oneCards) == 5) { // 看牌抢庄牛 === > 发3张牌（后两张）；
                        $fullC = implode(',', $oneCards);
                        $oneCards = array_slice($oneCards, 3); // 取后两张
                    }
                    $playerCards[$seatId] = [
                        "seatNo" => $seatId,
                        "cards" => $oneCards,
                        "step" => 1,
                        "remark" => $fullC
                    ];
                    if ($curUfd > 0) {
                        $pushOneObj = [ 'm' => BaseEnum::XYM_0X17, "data" => $playerCards[$seatId]];
                        AuthCommon::pushFrontWeb($curUfd, json_encode($pushOneObj));    // 发牌推送取实时的FD上
                    }
                }
            }
            
            // 启动牌值计算数据；====> 看牌过程
            $this->asycWaitDealCenter($gameRId, $room_No, $playerCards, $playerFds);
        } else {
            BaseEnum::Logger('发牌失败：PlayNiuNiu-(asycStartCards)-发牌；======>   失败 Fail !! -->  ' . $room_No, 'user-login');
        }
    }

    /**
     * 看牌结算处理；
     *
     * @param string $room_No
     * @param array $useCards
     * @param boolean $playerFds
     */
    protected function asycWaitDealCenter($gameRId, $gameNo, $useCards, $playerFds = FALSE)
    {
        $sleepTime = ($this->palycenterTimer_long + 3) * 1000;
        $gameAllData = BaseComm::distMemoryRooms($gameNo, FALSE); // 内存数据；
        $fjSta = isset($gameAllData['fjStatus']) ? intval($gameAllData['fjStatus']) : 0;
        $gamePlays = isset($gameAllData['lists']) ? $gameAllData['lists'] : FALSE; // 玩家列表；
        $playerFds = ! empty($gamePlays) ? array_column($gamePlays, "fd", "seatNo") : false; // 座位列表
        $Parms = [
            "gameNo" => $gameNo,
            "clientIds" => $playerFds,
            "status" => $fjSta
        ];
        $this->asycTimeStart($this->palycenterTimer_long, $gameNo, $Parms, function () use ($gameNo, $playerFds) {
            Timer::clear($this->baseOneTimer); // 推送谁还没有完成的；
            $fjDetail = BaseComm::distMemoryRooms($gameNo, FALSE);
            $betList = isset($fjDetail['lists']) ? $fjDetail['lists'] : false;
            // 下边玩家有几个还没推送拼牌的操作；
            $notPinfds = [];
            if (! empty($betList)) {
                // FD防变动
                $playerFds = ! empty($betList) ? array_column($betList, "fd", "seatNo") : false; // 使用最新数据
                BaseEnum::Logger('拼牌数据查找：PlayNiuNiu-(BaseDB::asycWaitDealCenter)-是否有未拼牌的：[asycWaitDealCenter]--->>>' . json_encode($betList), 'user-login');
                foreach ($betList as $siteid => $onep) {
                    if (isset($onep['pstatus']) && intval($onep['pstatus']) !== CardEnum::GAME_STEP_4 && isset($onep['fd'])) { // 还没拼牌玩家
                        $notPinfds[] = $siteid;
                    }
                }
                if (! empty($notPinfds)) {
                    foreach ($notPinfds as $seatNo) {
                        $data = [
                            "seatNo" => $seatNo,
                            "status" => 1,
                            "text" => "拼牌完成"
                        ]; // 推送给所有玩家，拼牌完成；
                        AuthCommon::pushFrontWeb($playerFds, json_encode([
                            'm' => BaseEnum::XYM_0X21,
                            "data" => $data
                        ])); // 推送
                    }
                }
            }
        });

        // 抢庄====倒计时15秒钟;
        $this->palycenterTimer = Timer::after($sleepTime, function () use ($gameRId, $useCards, $gameNo, $playerFds) {
            Timer::clear($this->baseOneTimer);
            Timer::clear($this->palycenterTimer);
            $allCards = [];
            // 房间信息
            $roomDetail = BaseComm::GameRoomDetail($gameRId);
            // 棋牌内容：
            $fjDetail = BaseComm::distMemoryRooms($gameNo, FALSE);
            $userbetList = false;
            if (! empty($fjDetail) && isset($fjDetail['lists'])) {
                $userbetList = $fjDetail['lists'];
                $playerFds = ! empty($userbetList) ? array_column($userbetList, "fd", "seatNo") : false; // FD防变动
            }
            BaseEnum::Logger("牛牛结算处理：PlayNiuNiu-(asycWaitDealCenter)-[roomid={$gameRId}]；======> Start ....-->UserList=" . json_encode($userbetList), 'user-login');
            BaseEnum::Logger("牛牛结算：PlayNiuNiu-(asycWaitDealCenter)-[roomid={$gameRId}]；======> getRoomInfo=" . json_encode($roomDetail), 'user-login');

            // 座位号
            $uSeatList = ! empty($userbetList) ? array_column($userbetList, null, 'seatNo') : false;

            // 比牌数据操作；$useCards
            $zjObject = false;
            if (! empty($useCards) && ! empty($uSeatList) && ! empty($userbetList)) {
                foreach ($useCards as $seatId => $cardinfo) {
                    $allCards[$seatId] = isset($cardinfo["cards"]) ? $cardinfo["cards"] : false; // 取牌数据
                    $useFo = isset($uSeatList[$seatId]) ? $uSeatList[$seatId] : false;
                    $useCards[$seatId]["userId"] = isset($useFo['uid']) ? intval($useFo['uid']) : 0;
                    $useCards[$seatId]["mainFlag"] = isset($useFo['mainflag']) ? intval($useFo['mainflag']) : 0; // 庄家标识
                    $useCards[$seatId]["mainMutle"] = isset($useFo['mutdotts']) ? intval($useFo['mutdotts']) : 1; // 下注或抢庄的倍数关系
                    if ($useCards[$seatId]["mainFlag"] === 1) {
                        $zjObject = $useCards[$seatId];
                        // 处理一下倍数关系统；至少1倍 mainMutle
                        unset($useCards[$seatId]); // 庄家牌内容
                    }
                }

                // 结算处理；
                BaseEnum::Logger('牛牛庄家：PlayNiuNiu-(asycWaitDealCenter)===-->' . json_encode($zjObject), 'user-login');
                BaseEnum::Logger('牛牛闲家：PlayNiuNiu-(asycWaitDealCenter)===-->' . json_encode($useCards), 'user-login');

                // 结算玩家的计算；把庄家跟闲家进行一一对比；
                $resultList = GameCommon::dealPlayMoney($gameRId, $gameNo, $zjObject, $useCards, $roomDetail); // 结算内容
                                                                                                               // 处理结果；谁赢钱；

                // 推送：所有牌数据和输赢；
                if (! empty($resultList) && sizeof($resultList) > 1) {

                    BaseEnum::Logger('牛牛结算处理：PlayNiuNiu-(asycWaitDealCenter)-；======> SUCCESS ....-->  ' . json_encode($resultList), 'user-login');
                    $fjDetail['fjStatus'] = CardEnum::GAME_STEP_5;
                    if (isset($fjDetail['lists']) && ! empty($fjDetail['lists'])) {
                        foreach ($fjDetail['lists'] as $setiid => $fg) {
                            $fjDetail['lists'][$setiid]["pstatus"] = CardEnum::GAME_STEP_5;
                        }
                    }
                    BaseComm::distMemoryRooms($gameNo, TRUE, $fjDetail); // 保存用户数据
                    BaseEnum::wirteRedisData(SysEnum::ONLINE_ROOMS_LIST_KEY . $gameNo, json_encode($fjDetail)); // 缓存；
                    foreach ($resultList as $setid => $res) {
                        if (! isset($res["cards"]) || empty($res["cards"])) {
                            $resultList[$setid]["cards"] = isset($allCards[$setid]) ? $allCards[$setid] : []; // 取牌数据
                        }
                    }

                    // 前端结算：
                    AuthCommon::pushFrontWeb($playerFds, json_encode([
                        'm' => BaseEnum::XYM_0X1C,
                        "data" => array_values($resultList)
                    ])); // 推送不同的数据；
                } else {
                    BaseEnum::Logger('牛牛结算处理：结算失败 ！！！！PlayNiuNiu-(asycWaitDealCenter)-；======>  ' . print_r($zjObject, true), 'user-login');
                    return false;
                }
            }
        });
    }
}

?>